/*~~~~~~~~~~~~~~~~~~~~~~
[Bot IRC]
Auteur: Thaeron
Projet: NewSyndrome
Version: 1.6.8
Licence: GPL

Copyright (C) 2004 - 2010 Thaeron

This program is free software; you can redistribute it and/or 
modify it under the terms of the GNU General Public License as 
published by the Free Software Foundation; either version 2 of the 
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but 
WITHOUT ANY WARRANTY; without even the implied warranty of 
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
General Public License for more details.

You should have received a copy of the GNU General Public License 
along with this program; if not, write to the Free Software 
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 
USA
~~~~~~~~~~~~~~~~~~~~~~*/

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <dirent.h>
#include <signal.h>
#include <stdarg.h>
#define byte char
#define CONF_COMMENT_CAR '%'

#define NS_VERSION "NewSyndrome 1.6.8"    /* MAJOR = 1 , MINOR = 6, SUB_MINOR = ? */
#define NS_VERSION_ID 10608		/* MAJOR*10000 + MINOR*100 + SUB_MINOR */

#ifndef DISABLE_ICONV
#include <iconv.h>
#define USE_ICONV(x) (!(x==(iconv_t)-1))
#endif


#ifdef WIN32
#include <windows.h>
#include <winbase.h>
#ifdef ENABLE_IPV6
	#if (_WIN32_WINNT < 0x0501)	/* ugly but it's necessary to compile and link*/
		#undef _WIN32_WINNT
		#define _WIN32_WINNT 0x501 
	#endif
	#include <ws2tcpip.h>
#else
	#include <winsock.h>
#endif
#include <process.h>
#define tMOD HMODULE
#define dlopen(x, RTLD_NOW) LoadLibrary(x)
#define dlsym(x,y) GetProcAddress(x,y)
#define dlclose(x) FreeLibrary(x)
#define delay(x) Sleep(x)
#define _(String) String

#else
	#ifdef NS_INTERNATIONALIZE
		#include <libintl.h>
		#include <locale.h>
		#define _(String) gettext(String)
	#else
		#define _(String) String
	#endif

#include <sys/stat.h>
#include <fcntl.h>

#include <dlfcn.h>
#define tMOD void *
#include <signal.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <setjmp.h>

#define closesocket(x) close(x)
#define delay(x) usleep(x * 1000)
#endif

#ifdef ENABLE_SSL_CONNECTION
	#ifdef SSL_FROM_OPENSSL
		#include <openssl/err.h>
		#include <openssl/ssl.h>
	#endif
	#ifdef SSL_FROM_GNUTLS
		#include <gnutls/gnutls.h>
	#endif
#endif


#if defined ENABLE_NS_MALLOC && !defined INTERNAL_NS_MALLOC
#undef malloc
#undef free
#undef calloc
#undef realloc
#undef strdup
#define malloc(x) ns_malloc(__FILE__,__LINE__,x)
#define free(x) ns_free(__FILE__,__LINE__,x)
#define calloc(x,y) ns_calloc(__FILE__,__LINE__,x,y)
#define realloc(x,y) ns_realloc(__FILE__,__LINE__,x,y)
#define strdup(x) ns_strdup(__FILE__,__LINE__,x)
void *ns_calloc (const char *file, int line, size_t nmemb, size_t size);
void *ns_malloc (const char *file, int line, size_t size);
void ns_free (const char *file, int line, void *ptr);
void *ns_realloc (const char *file, int line, void *ptr, size_t size);
char *ns_strdup (const char *file, int line, const char *s);
void ns_malloc_close (void);
void ns_malloc_show_leak (void);
#endif


enum
{ TYPE, CMD, MOT, HOOK_PV, HOOK_NOTICE, HOOK_TYPE };

enum
{ CLEAN, UNLOAD, LOAD, UNLINK, UPDATE, REHASH, REINIT };

enum
{ LOAD_OK, NO_MODULE, NO_IDENT, ALREADY_LOAD, UNLOAD_OK, ALREADY_UNLOAD, NO_CMD };

enum
{ BAD, GOOD };

enum
{ KERNEL, MODULE, UNLOAD_MODULE };

enum
{ NS_LOG_TMP, NS_LOG_HOME };

enum
{ CONF_DELETE_BY_KEY, CONF_DELETE_BY_VAL, CONF_UPDATE_VAL, CONF_ADD_KEY, CONF_COMMENT_LINE };

enum { NS_NO_SOCKET=-10, NS_CANNOT_RESOLVE, NS_CANNOT_CONNECT, NS_CANNOT_BIND };

enum
{ FD_CHECK_RD = 0, FD_CHECK_WR, FD_CHECK_RDWR };

enum
{ REMOVE_FD_HANDLER, KEEP_FD_HANDLER };



typedef struct _conf_bot conf_bot;
struct _conf_bot
{
	char *filename;
	char *nick;
	char *rn;
	char *ident;
	char *server;
	char *myip;
	char *root_path;
	char *bdd_path;
	char *charset_from;
	char *charset_to;
	char *nickserv_pass;
	char *server_pass;
	char *module_path;
	int port;
	int nbchan;
	char **channel;
	char car_cmd;
	byte af_default;
	int af_delay;
	int reco_delay;
	byte use_ssl;
};


typedef struct _msg msg;
typedef struct _func_list func_list;
typedef struct _timeout_list timeout_list;

typedef struct _func_list *ns_handler_t;
typedef struct _timeout_list *ns_timeout_t;
typedef struct _fd_list *ns_fd_t;

typedef byte (*timeout_func_type) (void);
typedef byte (*timeout_param_func_type) (void *);
typedef int (*func_type) (msg *);
typedef void (*init_module_type) (void);
typedef void (*init_dep_type) (const char *, void *);
typedef void (*module_signal_type) (byte, char **, int);
typedef byte (*fd_func_type) (int, void *);


typedef struct _chanmap chanmap;
typedef struct _usermap usermap;
struct _usermap
{
	char *nick;
	char *mask;
	byte modes;
	unsigned int cnb;
	chanmap **clist;
	usermap *next;
	usermap *prev;
};


struct _chanmap
{
	char *nom;
	unsigned int unb;
	usermap **ulist;
	chanmap *next;
	chanmap *prev;
};


typedef struct _fd_list fd_list;
struct _fd_list
{
	int fd;
	int mode;
	fd_func_type fd_func;
	void *arg_ptr;
	fd_list *next;
};


typedef struct _module module;
struct _module
{
	tMOD hd;
	char *name;
	char *ident;
	char *description;
	char *auteur;
	char *version;
	byte use_alarm;
	init_module_type init_module;
	init_dep_type init_dep;
	module_signal_type module_signal;
	func_list *func_head;
	func_list *hook_head;
	timeout_list *timeout_head;
	fd_list *fd_head;
	module *next;
};


struct _func_list
{
	char *cmd;
	byte mod;
	byte actif;
	void *userdata;
	func_type func;
	func_list *next;
};


struct _timeout_list
{
	int overtime;
	unsigned int last_exec;
	timeout_func_type timeout_func;
	timeout_param_func_type timeout_param_func;
	void *param;
	byte do_free;
	timeout_list *next;
};


struct _msg
{
	char **argu;
	int nbarg;
	char *sender;
	char *sender_nick;
	char *sender_ident;
	char *sender_host;
	char *cmd;
	char *dest;
	char *raw_txt;
	char **raw_tab;
	/*byte converted;*/
	char *argu_backend;
};


typedef struct _dep_link dep_link;
struct _dep_link
{
	char *nom;
	void *addr;
	dep_link *next;
};


typedef struct _core_bot core_bot;
struct _core_bot
{
	int sd;

	module *modlist;
	char *ns_log;

	byte log_default;
	byte bot_state;
	byte rehash;
  
	chanmap *chanmap_head;
	usermap *usermap_head;
	
	char *nom_conf;
	char *version;
	char *pidfile;
	
	time_t last_ping;
	unsigned int time_up, time_online;
	module *current_module;
	func_list *current_func;
	dep_link *dep_head;
	char extension[5];

#ifdef ENABLE_SSL_CONNECTION
#ifdef SSL_FROM_OPENSSL
	SSL_CTX *ctx;
	SSL *ssl;
#endif
#ifdef SSL_FROM_GNUTLS
	gnutls_certificate_credentials_t xcred;
	gnutls_session_t session;
#endif
#endif

#ifndef DISABLE_ICONV
	iconv_t ic_ext;
	iconv_t ic_int;
	iconv_t ic_valid;
#endif

#ifndef WIN32
	byte is_crashed;
	sigjmp_buf jmp_env;
#endif
};


typedef struct _identity identity;
struct _identity
{
	char *nick;
	char *ident;
	char *host;
};


typedef struct _module_list module_list;
struct _module_list
{
	char *name;
	char *ident;
	char *description;
	char *auteur;
	char *version;
	module_list *next;
};


typedef struct _conf_line conf_line;
struct _conf_line
{
	char *key;
	char *value;
};


/* Fonctions propres au kernel (conf.c & socket.c & init.c) */
void read_conf (conf_bot * bc, const char *nom);
int tcp_connect (const char *server_host, int port, const char *bind_ip);
#ifdef ENABLE_SSL_CONNECTION
int ssl_connect (void);
void ssl_free_all (void);
#endif
ssize_t ns_send (int s, const void *buf, size_t len, int flags);
ssize_t ns_recv (int s, void *buf, size_t len, int flags);
void connexion (void);
char *try_ns_log (int type);
int init_infolog (void);
void reception (conf_bot * bot);
void init_share_func (void);
void init_base (void);
void init_core (core_bot * cb);
void init_conv_charset (conf_bot * b);
void compar (msg *);
conf_line *conf_parse_line (const char *line);
/* gestion_requetes.c */
void gestion_requetes_modules (msg *);
void gestion_requetes_internes (msg *);
void gestion_hook (const char *, const char *, int);


/* Routines pour le kernel et les modules (routines.c) */
int cmpstar (const char *ref, const char *star);
char *str_replace (const char *data, const char *old_str, const char *new_str);
char *argu_to_string (char **argu, int nbarg, const char *radical, int depart);
char **string_to_argu (const char *str, char token, int allow_empty, int *nbelement); 	/* depuis 1.7 */
char *strf (const char *s, ...);
int identify_mask (identity * i, const char *m);
void free_identity (identity * a);
void clean_txt (char *txt);
void log_info (const char *merr);
void log_infof (const char *s, ...);
char *str_suppr (const char *buffer, const char *del);
char *multi_str_replace (const char *data, ...);
char *multi_str_suppr (const char *data, ...);
char *strpndup (const char *ptr_debut, const char *ptr_fin, int max); /* depuis 1.7 */


/* Routines du propres au kernel (kernel_fun.c) */
int kernel_addchan (conf_bot * bc, const char *n);
int kernel_delchan (conf_bot * bc, const char *n);
char *str_arg (const char *fmt, va_list ap);
int write_pid_file (const char *filename);
#ifndef WIN32
void daemonize (void);
int switch_user_group (char *user, char *group);
#endif

/* options.c */
int parse_options (int argc, char *argv[]);
#ifndef DISABLE_ICONV
int conv_charset (iconv_t p, const char *s_in, size_t ilen, char *s_out, size_t *olen);
int valid_charset (const char *s_in, size_t ilen);
#endif

/* parser.c */
int parse_buffer (msg * irc, char *buffer);
void free_msg (msg *irc);

/* Fonctions du mapping users/chans (userchan_map.c) */
chanmap *add_chanmap (chanmap * tete, const char *n);
usermap *add_usermap (usermap * tete, const char *n, const char *m);
chanmap *get_chanmap (chanmap * tete, const char *n);
usermap *get_usermap (usermap * tete, const char *n);
chanmap *del_chanmap (chanmap * tete, chanmap * ptr);
usermap *del_usermap (usermap * tete, usermap * ptr);
int unlink_chan2usermap (usermap * utmp, chanmap * chanx);
int unlink_chan2usermap (usermap * utmp, chanmap * chanx);
int link_user2chanmap (chanmap * ctmp, const char *n, const char *m);
int process_new_usermap (msg * i);
int process_del_usermap (const char *ou, const char *qui);
int process_pouf_usermap (const char *us);
int process_pouf_chanmap (const char *ch);
int process_new_chanmap (msg * i);
void update_map_nick (const char *onick, const char *nnick);
void update_map_mask (const char *nick, const char *mask);


/* API du bot pour les modules (bot.c) */
void log_module_info (const char *merr);
void log_module_infof (const char *s, ...);
void bot_set_ident_module (const char *n);
void bot_set_auteur_module (const char *n);
void bot_set_desc_module (const char *n);
void bot_set_version_module (const char *n);
void bot_send_privmsg (const char *dest, const char *str);
void bot_send_notice (const char *dest, const char *str);
void bot_send_raw (const char *str);
void bot_send_privmsgf (const char *dest, const char *s, ...);
void bot_send_noticef (const char *dest, const char *s, ...);
void bot_send_actionf (const char *dest, const char *s, ...);   /* depuis 1.6.5 */
void bot_send_action (const char *dest, const char *str);	/* depuis 1.6.5 */
void bot_send_rawf (const char *s, ...);
ns_handler_t bot_add_cmd_handler (const char *n, const char *fct);
int bot_rm_cmd_handler (const char *n);				/* depuis 1.6 */
ns_handler_t bot_add_type_handler (const char *n, const char *fct);
int bot_rm_type_handler (const char *n);			/* depuis 1.6 */
int bot_rm_handler (ns_handler_t hd);				/* depuis 1.7 */
void bot_unprotect_time_module (void);
void bot_protect_time_module (void);
int is_botnick (const char *n);
int bot_unload_module (const char *name);
int bot_load_module (const char *n);
void bot_actualise_ping (void);
unsigned int bot_get_time_up (void);
unsigned int bot_get_time_online (void);			/* depuis 1.7 */
char *bot_get_kernel_version (void);
void module_loader_add_link (const char *n, void * ad);
void module_loader_rm_link (const char *n);
conf_bot *bot_conf_get_addr (void);
ns_timeout_t bot_add_timeout_handler (int t, const char *fct);
ns_timeout_t bot_add_timeout_with_param_handler (int t, const char *fct, void *param_p, unsigned int size_p);
int bot_rm_timeout_handler (ns_timeout_t handler);		/* depuis 1.6.2 */
module_list *bot_get_module_list (void);
void bot_free_module_list (module_list * ml);
char *bot_get_info_from_conf (const char *base, unsigned int occur);
int bot_update_info_from_conf (const char *base, const char *value, const char *new_value, unsigned int mode); /* depuis 1.7 */
char **bot_get_userlist (const char *chan);
char **bot_get_chanlist (const char *user);
char *bot_get_mask (const char *user);
int bot_load_module_cmd (const char *cmd);
int bot_unload_module_cmd (const char *cmd);
int is_on_chan (const char *chan, const char *nick); 		/* depuis 1.6 */
void bot_set_handler_data (ns_handler_t handler, void *data); 	/* depuis 1.6 */
void *bot_get_handler_data (void); 				/* depuis 1.6 */
ns_handler_t bot_get_my_handle (void);			/* depuis 1.7 */
ns_handler_t bot_add_notice_hook (const char *fct);	/* depuis 1.6.2 */
ns_handler_t bot_add_privmsg_hook (const char *fct);	/* depuis 1.6.2 */
ns_handler_t bot_add_type_hook (const char *n, const char *fct);	/* depuis 1.6.2 */
ns_fd_t bot_add_fd_handler (int fd, int mode, const char *callback, void *arg);	/* depuis 1.7 */
int bot_rm_fd (int fd, int mode);	/* depuis 1.7 */
int bot_rm_fd_handler (ns_fd_t fd_hd);	/* depuis 1.7 */


/* Fonctions propres au kernel pour la gestion des modules (gestion_module.c & module_list.c & timeout.c) */
ns_fd_t add_module_fd (module *i, int fd, int mode, const char *callback, void *arg);
int rm_module_fd_by_handler (module *i, ns_fd_t fd_hd);
int rm_module_fd_by_fd (module *i, int fd, int mode);
void update_timeouts_time (int n_time);
void round_timeouts_modules (unsigned int now);
ns_timeout_t add_timeout (module * modone, const char *fct, int t);
ns_timeout_t add_timeout_with_param (module * modone, const char *fct, int t, void *param_p, unsigned int size_p);
void rm_all_timeouts (module *head);
int rm_timeout (module * modone, timeout_list * theone);
module *get_same_module_by_ident (module * i);
module *get_module (const char *n);
module *get_module_by_name (const char *name);
module *get_module_by_ident (const char *ident);
module *del_module (module * head, module * un);
module *add_module (module * head, const char *nem);
int kernel_unload_module (module * ptr);
ns_handler_t add_func (module * modone, const char *n, const char *fct, int mod);
int rm_func (module * modone, const char *n, int mod);
int rm_func_by_ptr (module * modone, func_list *ptr_one);
void broadcast_module_link (const char *n, void * ad);
void broadcast_module_signal (int mod_sig, char **tab, int nbarg);
module_list *add_element_module_list (module_list * ml, module * w);
void free_module_list (module_list * ml);
void free_bot_conf (conf_bot * b);

core_bot ns_core;
conf_bot ns_conf;
